package ru.zombator.taskman.client.actions;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.util.concurrent.TimeoutException;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Shell;

import ru.zombator.taskman.client.ui.ClientWindow;
import ru.zombator.taskman.client.ui.utils.UiUtils;
import ru.zombator.taskman.core.query.ITypedPacket;
import ru.zombator.taskman.core.query.TypedPacket;
import ru.zombator.taskman.core.query.payload.ErrorResponse;
import ru.zombator.taskman.core.query.payload.IPayload;

/**
 * Абстрактный класс для действий, открывающих диалог для сбора информации,
 * отправляющих запрос серверу и получающих ответ
 * 
 * @author nvamelichev
 * 
 */
public abstract class ADialogAction extends Action {
    protected ClientWindow mainWnd;
    
    public ADialogAction(ClientWindow mainWnd) {
        this.mainWnd = mainWnd;
    }
    
    /**
     * Создает диалоговое окно, открываемое для сбора данных от пользователя
     * 
     * @return диалог для ввода данных
     */
    protected abstract Dialog createDialog(Shell parentShell);
    
    /**
     * Создает запрос к серверу
     * 
     * @param dlg
     *            - диалог для ввода данных с заполненными полями
     * @return запрос к серверу
     */
    protected abstract IPayload createRequest(Dialog dlg);
    
    /**
     * Обрабатывает корректный ответ от сервера и выдает сообщение о результатах
     * обработки посланного запроса.
     * 
     * @param response
     *            - ответ сервера
     * @return сообщение о результатах, содержащихся в ответе сервера
     */
    protected abstract String processResponse(IPayload response);
    
    @Override
    public void run() {
        final Dialog dlg = createDialog(mainWnd.getShell());
        if (dlg.open() == IDialogConstants.OK_ID) {
            try {
                new ProgressMonitorDialog(mainWnd.getShell()).run(true, false,
                        new IRunnableWithProgress() {
                            @Override
                            public void run(IProgressMonitor monitor)
                                    throws InvocationTargetException, InterruptedException {
                                SubMonitor subPm = SubMonitor.convert(monitor,
                                        IProgressMonitor.UNKNOWN);
                                try {
                                    ITypedPacket response = mainWnd.getClient().sendPacket(
                                            new TypedPacket(createRequest(dlg)));
                                    Object responseObject = response.asObject();
                                    if (responseObject instanceof ErrorResponse) {
                                        throw new RemoteException(((ErrorResponse) response
                                                .asObject()).getMessage());
                                    } else {
                                        String info = processResponse((IPayload) responseObject);
                                        UiUtils.showInfo(info);
                                    }
                                } catch (TimeoutException e) {
                                    UiUtils.showError("Время ожидания ответа от сервера истекло.");
                                } catch (RemoteException e) {
                                    UiUtils.showError(String.format(
                                            "Не удалось выполнить запрос. Произошла ошибка:\n%s.",
                                            e.getMessage()));
                                } catch (IOException e) {
                                    UiUtils.showError("Не удалось связаться с сервером.");
                                } finally {
                                    if (subPm != null)
                                        subPm.done();
                                }
                            }
                        });
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
